﻿#region Copyright

/* 
 * Will Strohl (will.strohl@gmail.com)
 * http://www.willstrohl.com
 * 
 * Copyright (c) 2012, Will Strohl
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright notice, this list 
 * of conditions and the following disclaimer in the documentation and/or other 
 * materials provided with the distribution.
 * 
 * Neither the name of Will Strohl, SugarSync Folder Provider, nor the names of its 
 * contributors may be used to endorse or promote products derived from this software 
 * without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 */

#endregion

using System;
using System.Collections;
using System.Linq;
using System.Web.UI.WebControls;

using DotNetNuke.Entities.Host;
using DotNetNuke.Security;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.FileSystem;
using DotNetNuke.Services.Localization;

using HigLabo.Net.SugarSync;

namespace WillStrohl.Providers.SugarSyncFolderProvider
{
    ///<summary>
    /// SugarSync Settings Control
    ///</summary>
    public partial class Settings : FolderMappingSettingsControlBase
    {

        #region Constants

        private const string AccessKeyId = "AccessKeyId";
        private const string SecretAccessKey = "PrivateAccessKey";
        private const string Folder = "Folder";
        private const string Username = "Username";
        private const string Password = "Password";

        #endregion

        #region Private Variables

        private readonly string _encryptionKey = Host.GUID;
        private readonly PortalSecurity _portalSecurity = new PortalSecurity();
        private SugarSyncClient _client = null;

        private SugarSyncClient Client 
        { 
            get
            {
                if (_client != null) return _client;

                _client = new SugarSyncClient(txtUsername.Text.Trim(), txtPassword.Text.Trim(), txtAccessKeyId.Text.Trim(), txtPrivateAccessKey.Text.Trim());
                _client.Authenticate();

                return _client;
            } 
            set { _client = value; }
        }

        #endregion

        #region Overrided Methods

        /// <summary>
        /// Loads concrete settings.
        /// </summary>
        /// <param name="folderMappingSettings">The Hashtable containing the folder mapping settings.</param>
        public override void LoadSettings(Hashtable folderMappingSettings)
        {
            if (folderMappingSettings.ContainsKey(AccessKeyId))
            {
                txtAccessKeyId.Text = _portalSecurity.Decrypt(_encryptionKey, folderMappingSettings[AccessKeyId].ToString());
            }

            if (folderMappingSettings.ContainsKey(SecretAccessKey))
            {
                txtPrivateAccessKey.Text = _portalSecurity.Decrypt(_encryptionKey, folderMappingSettings[SecretAccessKey].ToString());
            }

            if (folderMappingSettings.ContainsKey(Username))
            {
                txtUsername.Text = _portalSecurity.Decrypt(_encryptionKey, folderMappingSettings[Username].ToString());
            }

            if (folderMappingSettings.ContainsKey(Password))
            {
                txtPassword.Text = _portalSecurity.Decrypt(_encryptionKey, folderMappingSettings[Password].ToString());
            }

            if (txtAccessKeyId.Text.Length > 0 && txtPrivateAccessKey.Text.Length > 0)
            {
                var folderName = string.Empty;

                if (folderMappingSettings.ContainsKey(Folder))
                {
                    folderName = folderMappingSettings[Folder].ToString();
                }

                LoadFolders();

                var folder = cboFolders.Items.FindByText(folderName);

                if (folder != null)
                {
                    cboFolders.SelectedIndex = cboFolders.Items.IndexOf(folder);
                }
            }
        }

        /// <summary>
        /// Updates concrete settings for the specified folder mapping.
        /// </summary>
        /// <param name="folderMappingID">The folder mapping identifier.</param>
        public override void UpdateSettings(int folderMappingID)
        {
            Page.Validate();

            if (!Page.IsValid)
            {
                throw new Exception();
            }

            var folderName = GetFolderName();

            var folderMappingController = FolderMappingController.Instance;
            var folderMapping = folderMappingController.GetFolderMapping(folderMappingID);

            var accessKeyId = GetAccessKeyId();
            var secretAccessKey = GetSecretAccessKey();
            var username = GetUsername();
            var password = GetPassword();

            if (AreThereFolderMappingsWithSameSettings(folderMapping, folderName))
            {
                cvFolderName.ErrorMessage = Localization.GetString("DuplicateFolders.ErrorMessage", LocalResourceFile);
                cvFolderName.IsValid = false;

                throw new Exception();
            }

            folderMapping.FolderMappingSettings[AccessKeyId] = accessKeyId;
            folderMapping.FolderMappingSettings[SecretAccessKey] = secretAccessKey;
            folderMapping.FolderMappingSettings[Folder] = folderName;
            folderMapping.FolderMappingSettings[Username] = username;
            folderMapping.FolderMappingSettings[Password] = password;

            folderMappingController.UpdateFolderMapping(folderMapping);
        }

        #endregion

        #region Private Methods

        private static bool AreThereFolderMappingsWithSameSettings(FolderMappingInfo folderMapping, string folderName)
        {
            var folderMappingController = FolderMappingController.Instance;
            var folderMappings = folderMappingController.GetFolderMappings(folderMapping.PortalID);

            return folderMappings.Any(existingFolderMapping => existingFolderMapping.FolderMappingID != folderMapping.FolderMappingID &&
                existingFolderMapping.FolderProviderType == folderMapping.FolderProviderType &&
                existingFolderMapping.FolderMappingSettings[Folder].ToString().Equals(folderName, StringComparison.InvariantCulture));
        }

        private bool CreateFolder(string folderName)
        {
            try
            {
                var cmd = new CreateFoldersCommand();
                cmd.DisplayName = _portalSecurity.InputFilter(txtFolderName.Text.Trim(), PortalSecurity.FilterFlag.NoMarkup);

                Client.CreateFolder(cmd);

                return true;
            }
            catch (Exception ex)
            {
                Exceptions.LogException(ex);
                cvFolderName.ErrorMessage = Localization.GetString("NewFolder.ErrorMessage", LocalResourceFile);
            }

            cvFolderName.IsValid = false;
            return false;
        }

        private string GetAccessKeyId()
        {
            return _portalSecurity.Encrypt(_encryptionKey, txtAccessKeyId.Text.Trim());
        }

        private string GetFolderName()
        {
            string folderName;

            if (cboFolders.Visible)
            {
                folderName = cboFolders.SelectedValue;
            }
            else
            {
                folderName = txtFolderName.Text.Trim();
                if (!CreateFolder(folderName)) throw new Exception();
            }

            return folderName;
        }
        
        private string GetSecretAccessKey()
        {
            return _portalSecurity.Encrypt(_encryptionKey, txtPrivateAccessKey.Text.Trim());
        }

        private string GetUsername()
        {
            return _portalSecurity.Encrypt(_encryptionKey, txtUsername.Text.Trim());
        }

        private string GetPassword()
        {
            return _portalSecurity.Encrypt(_encryptionKey, txtPassword.Text.Trim());
        }

        private void LoadFolders()
        {
            var contents = GetSugarSyncCollection("folders");

            try
            {
                foreach (var response in contents.Collections)
                {
                    cboFolders.Items.Add(response.DisplayName);
                }
            }
            catch (Exception ex)
            {
                cvFolderName.ErrorMessage = Localization.GetString("ListBuckets.ErrorMessage", LocalResourceFile);
                cvFolderName.IsValid = false;

                Exceptions.LogException(ex);
            }
        }

        private User GetSugarSyncUser()
        {
            return Client.GetUserInfo();
        } 

        private CollectionContents GetSugarSyncCollection(string collectionType)
        {
            var user = GetSugarSyncUser();

            var cmdCollection = new GetCollectionsCommand();
            switch (collectionType)
            {
                case "folders":
                    cmdCollection.Type = GetCollectionsCommandContentType.Folder;
                    break;
                case "files":
                    cmdCollection.Type = GetCollectionsCommandContentType.File;
                    break;
                default:
                    cmdCollection.Type = GetCollectionsCommandContentType.None;
                    break;
            }
            cmdCollection.Url = string.Format("https://api.sugarsync.com/user/{0}/{1}/contents", user.UserName, collectionType);

            return Client.GetCollections(cmdCollection);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// </summary>
        protected void cboFolders_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboFolders.SelectedIndex != 1) return;

            if (txtAccessKeyId.Text.Trim().Length > 0 && txtPrivateAccessKey.Text.Trim().Length > 0)
            {
                cboFolders.Items.Clear();

                cboFolders.Items.Add(Localization.GetString("SelectFolder", LocalResourceFile));
                cboFolders.Items.Add(Localization.GetString("RefreshFolderList", LocalResourceFile));

                LoadFolders();

                if (cboFolders.Items.Count == 3)
                {
                    // If there is only one bucket, then select it
                    cboFolders.SelectedValue = cboFolders.Items[2].Value;
                }
            }
            else
            {
                cvFolderName.ErrorMessage = Localization.GetString("CredentialsRequired.ErrorMessage", LocalResourceFile);
                cvFolderName.IsValid = false;
            }
        }

        /// <summary>
        /// </summary>
        protected void lnkNewFolder_Click(object sender, EventArgs e)
        {
            cboFolders.Visible = false;
            lnkNewFolder.Visible = false;
            txtFolderName.Visible = true;
            lnkSelectExistingFolder.Visible = true;
        }

        /// <summary>
        /// </summary>
        protected void btnSelectExistingBucket_Click(object sender, EventArgs e)
        {
            cboFolders.Visible = true;
            lnkNewFolder.Visible = true;
            txtFolderName.Visible = false;
            lnkSelectExistingFolder.Visible = false;
        }

        /// <summary>
        /// </summary>
        protected void valBucketName_ServerValidate(object source, ServerValidateEventArgs args)
        {
            if (cboFolders.Visible)
            {
                if (cboFolders.SelectedIndex > 1)
                {
                    args.IsValid = true;
                    return;
                }
            }
            else
            {
                if (txtFolderName.Text.Trim().Length > 0)
                {
                    args.IsValid = true;
                    return;
                }
            }

            cvFolderName.ErrorMessage = Localization.GetString("cvFolderName.ErrorMessage", LocalResourceFile);
            args.IsValid = false;
        }

        #endregion
    }
}
